
#include <nmds.h>

#ifdef __EXPORT__
#define extern __EXPORT__
#endif
extern FileTab cosmo_info;
extern boolean CScheckCosmoFile(FileInfoP fi);
extern boolean CSskipCosmoFile(FileInfoP fi,ErrorFuncP errfunc,int errlev,FileInfoP fcopy);
extern boolean CSreadCosmoFile(FileInfoP fi,EnsP ep,ErrorFuncP errfunc);
#undef extern

boolean CScheckCosmoFile(FileInfoP fi)
{
	long local_lc=0;
	char *s;
	boolean found_cosmo = FALSE;

	while ((s=CSgetFileCheckLine(NULL,fi))!=NULL) {
		if (strempty(s)) continue;
		local_lc++;
		if (!strncmp(s,"$cosmo",6)) found_cosmo = TRUE;
		if (local_lc>20 && !found_cosmo) return FALSE;
		if (*s!='$') continue;
		if (!strncmp(s,"$cosmo_data",11)) return TRUE;
	}
	return FALSE;
}

boolean CSskipCosmoFile(FileInfoP fi,ErrorFuncP errfunc,int errlev,FileInfoP fcopy)
{
	return CSgenericSingleRecordFileFormatCopy(fi,errfunc,errlev,fcopy);
}

boolean CSreadCosmoFile(FileInfoP fi,EnsP ep,ErrorFuncP errfunc)
{
	long local_lc = 0,block_lc,alabel;
	char *s,*s2,atag[10],gtag[10],sym[10],*eq;
	int l,gidx;
	PropAccess pac_sym,pac_xyz,pac_residue,pac_cdata,pac_alabel,pac_slabel;
	PropAccess pac_sxyz,pac_spot,pac_schrg,pac_sarea,pac_sareachrg;
	PropAccess pac_stype;
	float x,y,z;
	PropValue v;
	SurfaceP sp;
	enum { BLOCK_NONE,
		BLOCK_COSMO, BLOCK_COSMODATA, BLOCK_RAD, BLOCK_CAR, BLOCK_SCREEN,
		BLOCK_ENERGY,BLOCK_INFO,BLOCK_SEGMENT } block = BLOCK_NONE;
	boolean found_date,res;
	AtomP ap;

	if (!CSattachMultiProp((MajorobjP)ep,errfunc,
		A_SYMBOL,ATTACH_NONE,&pac_sym,
		A_XYZ,ATTACH_INITIALIZED,&pac_xyz,
		A_RESIDUE,ATTACH_INITIALIZED,&pac_residue,
		A_LABEL,ATTACH_NONE,&pac_alabel,
		(PropCode)"E_COSMO_DATA",ATTACH_INITIALIZED,&pac_cdata,
		O_LABEL,ATTACH_NONE,&pac_slabel,
		(PropCode)"O_XYZ",ATTACH_INITIALIZED,&pac_sxyz,
		(PropCode)"O_CHARGE",ATTACH_NONE,&pac_schrg,
		(PropCode)"O_AREACHARGE",ATTACH_NONE,&pac_sareachrg,
		(PropCode)"O_AREA",ATTACH_NONE,&pac_sarea,
		(PropCode)"O_POTENTIAL",ATTACH_NONE,&pac_spot,
		(PropCode)"O_TYPE",ATTACH_NONE,&pac_stype,
		E_NONE)) return FALSE;

	while ((s=CSgetFileLine(&l,fi))!=NULL) {
		 local_lc++;
		 if (strempty(s) || *s=='#') continue;
		 if (*s=='$') {
			 if (!strncmp(s,"$cosmo_data",11)) {
				 block = BLOCK_COSMODATA;
			 } else if (!strncmp(s,"$cosmo_energy",13)) {
				 block = BLOCK_ENERGY;
		  	 } else if (!strncmp(s,"$cosmo",6)) {
				 block = BLOCK_COSMO;
			 } else if (!strncmp(s,"$coord_rad",10)) {
				 block = BLOCK_RAD;
			 } else if (!strncmp(s,"$cosmo_info",11)) {
				 block = BLOCK_INFO;
			 } else if (!strncmp(s,"$coord_car",10)) {
				 block = BLOCK_CAR;
				 found_date = FALSE;
			 } else if (!strncmp(s,"$screening_charge",17)) {
				 block = BLOCK_SCREEN;
			 } else if (!strncmp(s,"$segment_information",13)) {
				 block = BLOCK_SEGMENT;
			 } else {
			 	block = BLOCK_NONE;
			 }
			 block_lc = 0;
			 continue;
		 }
		 block_lc++;
		 switch(block) {
			case BLOCK_COSMO:
			case BLOCK_COSMODATA:
			case BLOCK_SCREEN:
			case BLOCK_ENERGY:
			case BLOCK_INFO:
				eq = strchr(s,'=');
				if (eq==NULL) continue;
				*eq = 0;
				s2 = strchr(s,'[');
				if (s2!=NULL) *s2 = 0;
				strtrail(s,". ",0);
				s += strspn(s,STDSEP);
				strtranslate(s,STDSEP,"_");
				if (!CSstoreDictionaryField(&PV(pac_cdata,ep),
					s,strtrim(eq+1),FALSE,ep->context,errfunc)) return FALSE;
				break;
			case BLOCK_CAR:
				if (found_date) {
					if (!strlazycmp(s,"end")) continue;
					if (sscanf(s,"%8s%f%f%f%10s%d%*s%2s",atag,&x,&y,&z,gtag,&gidx,sym)==7) {
						ap = CScreateLinkedAtom(ep,DEFAULT_ATOM_BONDS,errfunc);
						if (ap==NULL) return FALSE;
						strncpy(PV_SHORTSTRING(pac_sym,ap),sym,SHORTSTRINGLEN);
						CStmpString(&v,strtrim(atag));
						CSreplaceNamedCompoundField(&pac_residue,(ChemobjP)ap,"atomtag",&v,FALSE);
						CStmpString(&v,strtrim(gtag));
						CSreplaceNamedCompoundField(&pac_residue,(ChemobjP)ap,"grouptag",&v,FALSE);
						PV_COMPOUND_NAMEFIELD(pac_residue,(ChemobjP)ap,"groupindex").l = gidx;
						PV_FLOATVECX(pac_xyz,ap) = x;
						PV_FLOATVECY(pac_xyz,ap) = y;
						PV_FLOATVECZ(pac_xyz,ap) = z;
					}
				} else {
					found_date = !strncmp(s,"!DATE",5);
				}
				break;
			case BLOCK_RAD:
				break;
			case BLOCK_SEGMENT:
				sp = (SurfaceP) CSlinkChemobj(CS_PAC_LIST(pac_slabel),1,INVAL_NEVER,FALSE,errfunc);
				if (sp==NULL) return FALSE;
				if (sscanf(s,"%ld%ld%f%f%f%lf%lf%lf%lf",
					&PV_INT(pac_slabel,sp),
					&alabel,
					&PV_FLOATVECX(pac_sxyz,sp),
					&PV_FLOATVECY(pac_sxyz,sp),
					&PV_FLOATVECZ(pac_sxyz,sp),
					&PV_DOUBLE(pac_schrg,sp),
					&PV_DOUBLE(pac_sarea,sp),
					&PV_DOUBLE(pac_sareachrg,sp),
					&PV_DOUBLE(pac_spot,sp))!=9) {
						return CSerror(errfunc,42,fi->status.lc,fi->status.rc);
					}
					sp->atoms[0] = CSfindLabelAtom(ep,alabel,FALSE,errfunc);
				PV_INT(pac_stype,sp) = SURFACE_POINT;
				break;
		 }
	}
	if (!found_date) return FALSE;
	CSsetEnsPropsValid(ep);
	CS_PAC_LIST(pac_slabel)->status.setup = TRUE;
	CSsetPacLock(&pac_residue,TRUE);
	CSsetPacLock(&pac_cdata,TRUE);
	res = CSgetConnectivity(ep,FALSE,NOTFOUND,errfunc);
	fi->status.rc++;
	fi->status.eor = EOR_ENS;
	return res;
}

FileTab cosmo_info = {
	{
		"COSMO",
		MYSELF,
		MYMAIL,
		"1.1",
		SOURCE_FILE_DATE,
		135,
		FALSE,
		"`COSMO' file format extension",
		NULL,
		NULL,
		NULL,
		SIGNATURE_NONE
	},
	"F_COSMO",
	"cosmo",
	"chemical/x-cosmo",
	NULL,
	NULL,
	{
		{ "cosmo",FILE_MOLECULE },
		{ "cos",FILE_MOLECULE },
	},
	CSskipCosmoFile,
	CSreadCosmoFile,
	NULL,
	CScheckCosmoFile,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	FFLAG_NOCHARGE|FFLAG_SINGLERECORD
};
